package org.dromara.system.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.entity.UploadResult;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysFaultFeedbackEn;
import org.dromara.system.domain.bo.SysFaultFeedbackEnAuditBo;
import org.dromara.system.domain.bo.SysFaultFeedbackEnBo;
import org.dromara.system.domain.bo.SysFaultFeedbackEnQueryBo;
import org.dromara.system.domain.vo.SysFaultFeedbackEnVo;
import org.dromara.system.mapper.SysFaultFeedbackEnMapper;
import org.dromara.system.service.ISysFaultFeedbackEnService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * English Fault Feedback Service Implementation
 *
 * @author system
 * @date 2025-10-10
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysFaultFeedbackEnServiceImpl implements ISysFaultFeedbackEnService {

    private final SysFaultFeedbackEnMapper baseMapper;

    /**
     * Feedback image configuration constants
     * ⭐ KEY CHANGE: English feedback folder
     */
    private static final String FEEDBACK_FOLDER = "feedback-en/";
    private static final int MAX_IMAGES = 3;
    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
    private static final String[] ALLOWED_TYPES = {"image/jpeg", "image/jpg", "image/png", "image/webp"};

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysFaultFeedbackEnVo submitFeedback(SysFaultFeedbackEnBo bo, MultipartFile[] files) {
        // 1. Validate image count
        if (files != null && files.length > MAX_IMAGES) {
            throw new ServiceException("Maximum " + MAX_IMAGES + " images can be uploaded");
        }

        // 2. Upload images to MinIO (eviton/feedback-en/ folder) ⭐ KEY CHANGE
        List<String> imageUrls = new ArrayList<>();
        if (files != null && files.length > 0) {
            OssClient ossClient = OssFactory.instance();
            for (MultipartFile file : files) {
                // Validate file size
                if (file.getSize() > MAX_FILE_SIZE) {
                    throw new ServiceException("Image size cannot exceed 5MB");
                }

                // Validate file type
                String contentType = file.getContentType();
                if (!isImageType(contentType)) {
                    throw new ServiceException("Only jpg, png, webp format images are supported");
                }

                try {
                    // Generate file name: feedback-en/uuid.ext ⭐ KEY CHANGE
                    String originalFilename = file.getOriginalFilename();
                    String extension = originalFilename != null && originalFilename.contains(".")
                        ? originalFilename.substring(originalFilename.lastIndexOf("."))
                        : ".jpg";
                    String fileName = FEEDBACK_FOLDER + IdUtil.fastSimpleUUID() + extension;

                    // Upload file (using InputStream method)
                    UploadResult uploadResult = ossClient.upload(
                        file.getInputStream(), 
                        fileName, 
                        file.getSize(), 
                        contentType
                    );
                    imageUrls.add(uploadResult.getUrl());
                } catch (Exception e) {
                    log.error("Image upload failed", e);
                    throw new ServiceException("Image upload failed: " + e.getMessage());
                }
            }
        }

        // 3. Build entity and save
        SysFaultFeedbackEn entity = MapstructUtils.convert(bo, SysFaultFeedbackEn.class);
        entity.setImageUrls(imageUrls);
        entity.setStatus("PENDING"); // Initial status: Pending

        baseMapper.insert(entity);

        // 4. Return detail
        return queryById(entity.getFeedbackId());
    }

    @Override
    public TableDataInfo<SysFaultFeedbackEnVo> queryPageList(SysFaultFeedbackEnQueryBo queryBo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysFaultFeedbackEn> lqw = buildQueryWrapper(queryBo);
        Page<SysFaultFeedbackEnVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        // Fill status name
        result.getRecords().forEach(this::fillStatusName);
        return TableDataInfo.build(result);
    }

    @Override
    public List<SysFaultFeedbackEnVo> queryList(SysFaultFeedbackEnQueryBo queryBo) {
        LambdaQueryWrapper<SysFaultFeedbackEn> lqw = buildQueryWrapper(queryBo);
        List<SysFaultFeedbackEnVo> list = baseMapper.selectVoList(lqw);
        // Fill status name
        list.forEach(this::fillStatusName);
        return list;
    }

    @Override
    public SysFaultFeedbackEnVo queryById(Long feedbackId) {
        SysFaultFeedbackEnVo vo = baseMapper.selectVoById(feedbackId);
        if (vo != null) {
            fillStatusName(vo);
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean auditFeedback(SysFaultFeedbackEnAuditBo auditBo) {
        // 1. Query if feedback exists
        SysFaultFeedbackEn entity = baseMapper.selectById(auditBo.getFeedbackId());
        if (entity == null) {
            throw new ServiceException("Feedback record does not exist");
        }

        // 2. Validate status (can only audit pending records)
        if (!"PENDING".equals(entity.getStatus())) {
            throw new ServiceException("This feedback has been audited and cannot be repeated");
        }

        // 3. Update audit information
        entity.setStatus(auditBo.getStatus());
        entity.setAuditRemark(auditBo.getAuditRemark());
        entity.setAuditBy(LoginHelper.getUserId());
        entity.setAuditTime(new Date());

        return baseMapper.updateById(entity) > 0;
    }

    /**
     * Build query conditions
     */
    private LambdaQueryWrapper<SysFaultFeedbackEn> buildQueryWrapper(SysFaultFeedbackEnQueryBo queryBo) {
        LambdaQueryWrapper<SysFaultFeedbackEn> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(queryBo.getExcavatorModel()), SysFaultFeedbackEn::getExcavatorModel, queryBo.getExcavatorModel());
        lqw.eq(StringUtils.isNotBlank(queryBo.getFaultPart()), SysFaultFeedbackEn::getFaultPart, queryBo.getFaultPart());
        lqw.eq(StringUtils.isNotBlank(queryBo.getFaultSymptom()), SysFaultFeedbackEn::getFaultSymptom, queryBo.getFaultSymptom());
        lqw.eq(StringUtils.isNotBlank(queryBo.getStatus()), SysFaultFeedbackEn::getStatus, queryBo.getStatus());
        lqw.eq(queryBo.getCreateUserId() != null, SysFaultFeedbackEn::getCreateBy, queryBo.getCreateUserId());
        lqw.between(queryBo.getBeginTime() != null && queryBo.getEndTime() != null,
            SysFaultFeedbackEn::getCreateTime, queryBo.getBeginTime(), queryBo.getEndTime());
        lqw.orderByDesc(SysFaultFeedbackEn::getCreateTime);
        return lqw;
    }

    /**
     * Validate file type
     */
    private boolean isImageType(String contentType) {
        if (contentType == null) {
            return false;
        }
        for (String allowedType : ALLOWED_TYPES) {
            if (contentType.toLowerCase().contains(allowedType.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

    /**
     * Fill status name and default values
     */
    private void fillStatusName(SysFaultFeedbackEnVo vo) {
        // Fill status name
        if (vo.getStatus() != null) {
            switch (vo.getStatus()) {
                case "PENDING":
                    vo.setStatusName("Pending");
                    break;
                case "APPROVED":
                    vo.setStatusName("Approved");
                    break;
                case "REJECTED":
                    vo.setStatusName("Rejected");
                    break;
                default:
                    vo.setStatusName(vo.getStatus());
            }
        }
        
        // Set empty string default for null fields (avoid front-end validation errors)
        if (vo.getRemark() == null) {
            vo.setRemark("");
        }
        if (vo.getAuditRemark() == null) {
            vo.setAuditRemark("");
        }
        if (vo.getAuditByName() == null) {
            vo.setAuditByName("");
        }
    }

}

